package research.ui.editors;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.ComboViewer;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.forms.widgets.Section;
import org.eclipse.ui.forms.widgets.TableWrapData;

import research.domain.Calander;
import research.domain.DefaultParameterValue;
import research.domain.FilmType;
import research.domain.Parameter;
import research.entity.Entity;
import research.entity.EntityFactory;
import research.entity.EntityType;
import research.model.CalanderHierarchy;
import research.model.EntityListContentProvider;
import research.model.ListHierarchy;
import research.model.ParameterHierarchy;
import research.persistence.PersistenceManager;
import research.ui.editors.input.EntityEditorInput;
import research.ui.editors.tableeditors.filmtype.FilmTypeTableEditor;

public class FilmTypeEditor extends FormEntityEditor {
	public static String ID = "research.ui.editors.FilmTypeEditor";
	private Text name;
	private Text description;
	private Button hasViscosity;
	private Button hasStrength;
	private Button hasPhoto;
	private Button hasScratch;
	private Button hasStabilizer;
	private ComboViewer calander;
	
	private FilmTypeTableEditor valuesEditor;
	private Map<Entity, List<Entity>> values;
	private Map<Entity, List<Entity>> initValues;
	
	private FilmType getEntity() {
		return (FilmType) entity;
	}

	@Override
	protected boolean checkInputEntityType(EntityEditorInput input) {
		return input.getEntity().getType().equals(EntityType.FilmType);
	}

	@Override
	protected void fill() {
		this.name.setText(this.getEntity().getName());
		this.description.setText(this.getEntity().getDescription());
		this.hasViscosity.setSelection(this.getEntity().isHasViscosity());
		this.hasStrength.setSelection(this.getEntity().isHasStrength());
		this.hasPhoto.setSelection(this.getEntity().isHasPhoto());
		this.hasScratch.setSelection(this.getEntity().isHasScratch());
		this.hasStabilizer.setSelection(this.getEntity().isHasStabilizer());
		
		updateTable();
	}

	@Override
	protected void initialize() {
		values = new HashMap<Entity, List<Entity>>();
		initValues = new HashMap<Entity, List<Entity>>();
		
		for (Entity entity : PersistenceManager.getInstance().getDataSource().getAll(EntityType.Calander)) {
			Calander calander = (Calander) entity;
			
			List<Entity> defValues = new ArrayList<Entity>();
			List<Entity> initDefValues = new ArrayList<Entity>();
			
			for (Entity e : PersistenceManager.getInstance().getDataSource().getChildren(calander, new CalanderHierarchy())) {
				Parameter parameter = (Parameter) e;
				
				DefaultParameterValue value = null;
				DefaultParameterValue defValue = null;
				
				for (Entity val : PersistenceManager.getInstance().getDataSource().getChildren(parameter, new ParameterHierarchy())) {
					DefaultParameterValue v = (DefaultParameterValue) val;
					if (v.getFilmType().equals(getEntity())) {
						value = v;
						defValue = (DefaultParameterValue) PersistenceManager.getInstance().getDataSource().get(EntityType.DefaultParameterValue, value.getId());
					}
				}
				
				if (value == null) {
					value = (DefaultParameterValue) EntityFactory.getNew(EntityType.DefaultParameterValue, getEntity());
					value.setParameter(parameter);
					value.setValue(Double.NaN);
				}
				
				defValues.add(value);
				
				if (defValue != null)
					initDefValues.add(defValue);
			}
			
			values.put(calander, defValues);
			initValues.put(calander, initDefValues);
		}
	}
	
	@Override
	protected void persist() {
		for (Entity e : initValues.keySet()) {
			Calander cal = (Calander) e;
			for (Entity ent : initValues.get(cal)) {
				DefaultParameterValue val = (DefaultParameterValue) ent;
				
				DefaultParameterValue newVal = null;
				for (Entity entity : values.get(cal)) {
					DefaultParameterValue v = (DefaultParameterValue) entity;
					if (v.equals(val))
						newVal = v;
				}
				
				if (Double.isNaN(newVal.getValue()))
					getPersistenceManager().remove(val);
				
			}
		}
		
		for (Entity e : values.keySet()) {
			Calander cal = (Calander) e;
			for (Entity ent : values.get(cal)) {
				DefaultParameterValue val = (DefaultParameterValue) ent;
				if (!Double.isNaN(val.getValue()))
					getPersistenceManager().persist(val);
			}
		}
	}

	@Override
	protected boolean readAndValidate() {
		this.getEntity().setName(this.name.getText());
		this.getEntity().setDescription(this.description.getText());
		this.getEntity().setHasViscosity(this.hasViscosity.getSelection());
		this.getEntity().setHasStrength(this.hasStrength.getSelection());
		this.getEntity().setHasPhoto(this.hasPhoto.getSelection());
		this.getEntity().setHasScratch(this.hasScratch.getSelection());
		this.getEntity().setHasStabilizer(this.hasStabilizer.getSelection());
		
		for (Entity e : values.keySet()) {
			Calander cal = (Calander) e;
			for (Entity ent : values.get(cal)) {
				DefaultParameterValue val = (DefaultParameterValue) ent;
				if (!Double.isNaN(val.getValue()))
					if (val.getValue() < val.getParameter().getLow() || val.getValue() > val.getParameter().getHigh()) {
						MessageDialog.openWarning(getSite().getShell(), "Error", "Регламентное значение параметра выходит за рамки ограничений для данного типа оборудования:\n" + val.getParameter().getCalander().getName() + " - " +  val.getParameter().getName());
						return false;
					}
						
			}
		}

		return validateText(name);
	}

	@Override
	protected void renderForm() {
		TableWrapData td;
		Section section;
		Composite composite;
		GridData gd;
		Label label;
		
		/*
		 * Name
		 */
		section = toolkit.createSection(form.getBody(), Section.TITLE_BAR);
		td = new TableWrapData(TableWrapData.FILL);
		section.setLayoutData(td);
		section.setText("Название*");
		composite = toolkit.createComposite(section);
		composite.setLayout(new GridLayout(1, false));
		section.setClient(composite);
		gd = new GridData(GridData.GRAB_HORIZONTAL | GridData.FILL_HORIZONTAL);
		name = toolkit.createText(composite, "",
				SWT.BORDER);
		gd.widthHint = 100;
		name.setLayoutData(gd);
		name.addModifyListener(getNameModifyListener());
		
		/*
		 * Has Viscosity
		 */
		section = toolkit.createSection(form.getBody(), Section.TITLE_BAR);
		td = new TableWrapData(TableWrapData.FILL);
		section.setLayoutData(td);
		section.setText("Актуальные стандартные испытания:");
		composite = toolkit.createComposite(section);
		composite.setLayout(new GridLayout(1, false));
		section.setClient(composite);
		gd = new GridData(GridData.GRAB_HORIZONTAL | GridData.FILL_HORIZONTAL);
		hasViscosity = toolkit.createButton(composite, "Испытание ударной вязкости", SWT.CHECK);
		gd.widthHint = 200;
		hasViscosity.setLayoutData(gd);
		hasViscosity.addSelectionListener(getDateSelectionListener());
		
		/*
		 * Has Strength
		 */
		gd = new GridData(GridData.GRAB_HORIZONTAL | GridData.FILL_HORIZONTAL);
		hasStrength = toolkit.createButton(composite, "Испытание на прочность при растяжении", SWT.CHECK);
		gd.widthHint = 200;
		hasStrength.setLayoutData(gd);
		hasStrength.addSelectionListener(getDateSelectionListener());
		
		/*
		 * Has Photo
		 */
		gd = new GridData(GridData.GRAB_HORIZONTAL | GridData.FILL_HORIZONTAL);
		hasPhoto = toolkit.createButton(composite, "Испытание способности к печати", SWT.CHECK);
		gd.widthHint = 200;
		hasPhoto.setLayoutData(gd);
		hasPhoto.addSelectionListener(getDateSelectionListener());
		
		/*
		 * Has Scratch
		 */
		gd = new GridData(GridData.GRAB_HORIZONTAL | GridData.FILL_HORIZONTAL);
		hasScratch = toolkit.createButton(composite, "Испатание стойкости к царапинам", SWT.CHECK);
		gd.widthHint = 200;
		hasScratch.setLayoutData(gd);
		hasScratch.addSelectionListener(getDateSelectionListener());
		
		/*
		 * Has Stabilizer
		 */
		gd = new GridData(GridData.GRAB_HORIZONTAL | GridData.FILL_HORIZONTAL);
		hasStabilizer = toolkit.createButton(composite, "Испытание стабилизатора", SWT.CHECK);
		gd.widthHint = 200;
		hasStabilizer.setLayoutData(gd);
		hasStabilizer.addSelectionListener(getDateSelectionListener());
		
		/*
		 * Description
		 */
		section = toolkit.createSection(form.getBody(), Section.TITLE_BAR);
		td = new TableWrapData(TableWrapData.FILL_GRAB);
		section.setLayoutData(td);
		section.setText("Описание");
		composite = toolkit.createComposite(section);
		composite.setLayout(new GridLayout(1, false));
		section.setClient(composite);
		gd = new GridData(GridData.GRAB_HORIZONTAL | GridData.FILL_HORIZONTAL);
		description = toolkit.createText(composite, "",
				SWT.BORDER | SWT.MULTI | SWT.WRAP | SWT.V_SCROLL);
		gd.widthHint = 200;
		gd.heightHint = 60;
		description.setLayoutData(gd);
		description.addModifyListener(getTextModifyListener());
		
		/*
		 * Default values
		 */
		section = toolkit.createSection(form.getBody(), Section.TITLE_BAR);
		td = new TableWrapData(TableWrapData.FILL);
		section.setLayoutData(td);
		section.setText("Рекомендуемые значения технологических параметров для оборудования:");
		composite = toolkit.createComposite(section);
		composite.setLayout(new GridLayout(1, false));
		section.setClient(composite);
		
		gd = new GridData();
		label = toolkit.createLabel(composite, "Каландровая линия:");
		label.setLayoutData(gd);
		gd = new GridData(GridData.GRAB_HORIZONTAL | GridData.FILL_HORIZONTAL);
		calander = new ComboViewer(composite, SWT.DROP_DOWN
				| SWT.READ_ONLY);
		calander.setContentProvider(new EntityListContentProvider(new ListHierarchy(EntityType.Calander), false));
		calander.setLabelProvider(new LabelProvider());
		calander.setInput(PersistenceManager.getInstance());
		gd.widthHint = 100;
		calander.getCombo().setLayoutData(gd);
		
		calander.getCombo().addModifyListener(new CalanderModifyListener());
		
		/*
		 * Default values table
		 */
		valuesEditor = new FilmTypeTableEditor(composite);

	}
	
	private void updateTable() {
		List<Entity> input = new ArrayList<Entity>();
		Calander cal = (Calander) getComboEntity(calander);
		if (cal != null)
			for (Entity entity : values.keySet()) {
				Calander calander = (Calander) entity;
				if (cal.equals(calander))
					input = values.get(calander);
			}
			
		valuesEditor.setInput(input);
		valuesEditor.addModifyListener(getEntityTableListener());
	}
	
	public class CalanderModifyListener implements ModifyListener {
		@Override
		public void modifyText(ModifyEvent e) {
			updateTable();
		}
	}

}
